/*
 * Copyright 2007 (c) Tim Knip, ascollada.org.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
 
package  
{
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.display.StageQuality;
	import flash.events.*;
	import flash.geom.Point;
	import flash.system.Capabilities;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.ui.Keyboard;
	import flash.utils.ByteArray;
		
	import org.ascollada.utils.*;
	
	import org.papervision3d.Papervision3D;
	import org.papervision3d.cameras.*;
	import org.papervision3d.core.*;
	import org.papervision3d.core.proto.*;
	import org.papervision3d.events.*;
	import org.papervision3d.materials.*;
	import org.papervision3d.objects.*;
	import org.papervision3d.scenes.*;
	
	/**
	 * 
	 */
	public class Main extends Sprite
	{
		/** sprite to render to */
		public var container:Sprite;
		
		/** pv3d scene */
		public var scene:Scene3D;
		
		/** pv3d camera */
		public var camera:FreeCamera3D;
		
		/** collada example */
		public var dae:DAE;
	
		public var obj:DisplayObject3D;
		
		[Embed (source="../../../../../../trunk/meshes/xwing.dae", mimeType="application/octet-stream")]
		public var houndClass:Class;
		
		[Embed (source="../../../../../../trunk/image/xwingskin.jpg")]
		public var houndTextureClass:Class;
		
		public var doAnimateExhausts:Boolean = false;
		public var animatedSkin_mc:MovieClip;
		public var speed:Number = 0;
		public var moveForward:Boolean;
		public var moveBackward:Boolean;
		public var moveLeft:Boolean;
		public var moveRight:Boolean;
		
		/**
		 * 
		 * @return
		 */
		public function Main():void
		{
			init();
		}
		
		/**
		 * 
		 * @return
		 */
		private function init():void
		{
			this.stage.quality = StageQuality.LOW;
			
			//Papervision3D.VERBOSE = false;
			
			MaterialObject3D.DEFAULT_COLOR = 0xcccccc;
			
			_status = new TextField();
			addChild(_status);
			_status.x = _status.y = 5;
			_status.width = 300;
			_status.height = 100;
			_status.selectable = false;
			_status.multiline = true;
			_status.defaultTextFormat = new TextFormat( "Arial", 11, 0xffff00 );
			
			this.container = new Sprite();
			addChild(this.container);
			this.container.x = 400;
			this.container.y = 300;

			_lastMouse = new Point();
			
			//stage.addEventListener( KeyboardEvent.KEY_UP, keyUpHandler );
			stage.addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
			stage.addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
			stage.addEventListener( MouseEvent.MOUSE_MOVE, mouseMoveHandler );
			
			var materialsList:MaterialsList = new MaterialsList();
			var texture:Bitmap = new houndTextureClass();
			
			materialsList.addMaterial( new BitmapMaterial(texture.bitmapData), "xwingTexture" );
			
			this.dae = new DAE( "../../../../../trunk/meshes/boxes-cameras.DAE" );
			
			this.dae.addEventListener( Event.COMPLETE, init3D );
			this.dae.addEventListener( ProgressEvent.PROGRESS, loadProgressHandler );
			this.dae.addEventListener( FileLoadEvent.LOAD_COMPLETE, materialCompleteHandler );
			
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, onStageKeyUp);
		}
		
		/**
		 * 
		 * @param	event
		 * @return
		 */
		private function init3D( event:Event = null ):void
		{
			if( this.dae.hasEventListener(ProgressEvent.PROGRESS) )
				this.dae.removeEventListener(ProgressEvent.PROGRESS, loadProgressHandler);
				
			this.dae.addEventListener( ProgressEvent.PROGRESS, animationProgressHandler );
			
			Logger.trace( "init3D" );
			
			this.scene = new Scene3D(this.container);
			
			this.scene.addChild(this.dae);
			
			var zoom:Number = 300;
			var camdist:Number = 1000;
						
			this.camera = new FreeCamera3D(3, 200);
			//this.camera.z = -50;
			
			//this.dae.rootNode.rotationX = -90;
			
			//this.camera.lookAt(DisplayObject3D.ZERO);
			
			//this.camera.lookAt(this.dae);
			
			//this.obj = this.dae.getChildByName("Sphere01-node");
			loop3D();
			
			_status.text = Capabilities.version;
			
			addEventListener(Event.ENTER_FRAME, loop3D);
		}
		
		/**
		 * 
		 * @param	event
		 * @return
		 */
		private function loop3D( event:Event = null ):void
		{
			//this.obj.rotationY++;
			//this.dae.rootNode.rotationY++;
			moveXWing();
			
			//this.dae.rotationY++;
			this.scene.renderCamera(camera);
			
			//_theta += Math.PI / 720;
			//_phi += Math.PI / 1440;
			//_phi = _phi % Math.PI;
			
			//orbitCamera( _theta, _phi );
			
		}
		
		/**
		 * 
		 * @param	event
		 */
		private function materialCompleteHandler( event:Event ):void 
		{
			//loop3D();
		}
				
		/**
		 * 
		 * @param	event
		 */
		private function animationProgressHandler( event:ProgressEvent ):void 
		{
			if( event.bytesLoaded == event.bytesTotal )
			{
				_status.text = "";
				addEventListener(Event.ENTER_FRAME, loop3D);
				
				this.dae.controller.addEventListener( ProgressEvent.PROGRESS, frameProgressHandler );
					
				this.dae.controller.repeatCount = 0;
				this.dae.controller.play();
			}
			else
			{
				var v:String = Capabilities.version;
				
				_status.text = v + "\nloading animation #" + event.bytesLoaded + " of " + event.bytesTotal;
			}
		}
		
		/**
		 * 
		 * @param	event
		 * @return
		 */
		private function frameProgressHandler( event:ProgressEvent ):void
		{
			_status.text = "frame #" + event.bytesLoaded + " of " + event.bytesTotal;
		}
		
		private function onStageKeyDown(event:KeyboardEvent):void
		{
			var keyCode:int = event.keyCode;
			switch(keyCode){
				case Keyboard.UP:
					moveForward = true;
				break;
				case Keyboard.DOWN:
					moveBackward = true;
				break;
				case Keyboard.LEFT:
					moveLeft = true;
				break;
				case Keyboard.RIGHT:
					moveRight = true;
				break;
			}
		}
		
		private function onStageKeyUp(event:KeyboardEvent):void
		{
			var keyCode:int = event.keyCode;
			switch(keyCode){
				case Keyboard.UP:
					moveForward = false;
				break;
				case Keyboard.DOWN:
					moveBackward = false;
				break;
				case Keyboard.LEFT:
					moveLeft = false;
				break;
				case Keyboard.RIGHT:
					moveRight = false;
				break;
			}
		}
		
		private function keyUpHandler(event:KeyboardEvent):void
		{
			var keyCode:int = event.keyCode;
			switch(keyCode){
				case "W".charCodeAt():
					camera.z++;
				break;
				case "S".charCodeAt():
					camera.z--;
				break;
				case "A".charCodeAt():
					camera.zoom++;
				break;
				case "D".charCodeAt():
					camera.zoom--;
				break;
			}
		}
		
		private function moveXWing():void
		{
			speed *=.98;
			var moving:Boolean = false;
			if(moveForward){
				speed+=2;
				moving = true;
				dae.pitch(1);
			}else if(moveBackward){
				moving = true;
				speed-=1;
				dae.pitch(-1);
			}
			
			//dae.moveForward(speed);
			
			if(moveLeft){
				moving = true;
				dae.yaw(-1);
			}else if(moveRight){
				moving = true;
				dae.yaw(1);
			}
		}
		
		/**
		 * 
		 * @param	event
		 */
		private function loadProgressHandler( event:ProgressEvent ):void 
		{
			var perc:Number = (event.bytesLoaded/event.bytesTotal) * 100;
			var megs:Number = event.bytesTotal / 1000 / 1000;
			
			_status.text = "\nloading: " + this.dae.fileTitle + " " + perc.toFixed(2) + "% done.";
		}
		
		/**
		 * 
		 * @param	event
		 * @return
		 */
		private function mouseDownHandler( event:MouseEvent ):void
		{
			_lastMouse.x = event.stageX;
			_lastMouse.y = event.stageY;
			_orbiting = true;
		}
		
		/**
		 * 
		 * @param	event
		 * @return
		 */
		private function mouseUpHandler( event:MouseEvent ):void
		{
			_orbiting = false;
		}
		
		/**
		 * 
		 * @param	event
		 * @return
		 */
		private function mouseMoveHandler( event:MouseEvent ):void
		{
			var dx:Number = event.stageX - _lastMouse.x;
			var dy:Number = event.stageY - _lastMouse.y;
			
			if( _orbiting && dae )
			{
				_lastMouse.x = event.stageX;
				_lastMouse.y = event.stageY;
			}
		}
		
		private function orbitCamera( theta:Number, phi:Number ):void
		{
			var r:Number = _dolly;
			
			var cosTheta:Number = Math.cos(theta);
			var sinTheta:Number = Math.sin(theta);
			var cosPhi:Number = Math.cos(phi);
			var sinPhi:Number = Math.sin(phi);
			
			camera.x = r * cosTheta * sinPhi;
			camera.z = r * sinTheta * sinPhi;
			camera.y = r * cosPhi;
			
			camera.lookAt(dae);
		}
		
		private var _status:TextField;
				
		private var _animate:Boolean = true;
		
		private var _orbiting:Boolean = false;
		
		private var _lastMouse:Point;
		
		private var _theta:Number = Math.PI/3;
		
		private var _phi:Number = Math.PI/2;
		
		private var _dolly:Number = 100;
	}
}
